// mutex.h -- Multiprocessor safe mutexes

/*
   Copyright 2006 Corey Tabaka

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

#ifndef __MUTEX_H__
#define __MUTEX_H__

#include <ktypes.h>
#include <spinlock.h>

#ifndef NULL
#define NULL 0
#endif

/*
 * Interrupt Mutexes
 */

#define INT_MUTEX_UNLOCKED { SPINLOCK_UNLOCKED, 0 }
#define INT_MUTEX_LOCKED { SPINLOCK_LOCKED, 0 }

typedef struct {
	spinlock_t spinlock;		// must be the first element in the structure
	uint32 flag __attribute__((packed));
} int_mutex_t;

#ifdef __cplusplus
extern "C" {
#endif

void interrupt_mutex_init(int_mutex_t *);
void interrupt_mutex_wait(int_mutex_t *);
void interrupt_mutex_signal(int_mutex_t *);

/*
 * Standard Mutexes
 */

#if 1
typedef struct _mutex_tid_node {
	struct _mutex_tid_node *next, *prev;
	
	// id of the waiting task
	tid_t tid;
} mutex_tid_node;

typedef struct {
	int_mutex_t lock;
	volatile int count;
	
	// queue of tasks waiting on this mutex
	mutex_tid_node *head, *tail;
} mutex_t;

#define MUTEX_UNLOCKED { INT_MUTEX_UNLOCKED, 0, NULL, NULL }
#define MUTEX_LOCKED { INT_MUTEX_UNLOCKED, 1, NULL, NULL }

void mutex_init(mutex_t *mutex);
void mutex_wait(mutex_t *mutex);
int mutex_try(mutex_t *mutex);
void mutex_signal(mutex_t *mutex);

#endif // if 0

/*
 * Semaphore
 */

typedef mutex_t semaphore_t;

#define SEMAPHORE_INIT(count) { INT_MUTEX_UNLOCKED, (count), NULL, NULL }
	 
void semaphore_init(semaphore_t *, int);
void semaphore_wait(semaphore_t *);
void semaphore_signal(semaphore_t *);

#ifdef __cplusplus
}
#endif

#endif
